﻿using CloudStorageLight.Core.Web;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace CloudStorageLight.Core
{
    /// <summary>
    /// Blobのコンテナ
    /// </summary>
    public abstract class BlobContainer : IDisposable
    {
                /// <summary>
        /// コンテナで利用している容量サイズを返す
        /// </summary>
        /// <returns></returns>
        public abstract Task<long> GetContainerSizeAsync();
        
        /// <summary>
        /// Blobディレクトリオブジェクトを生成する
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fetch"></param>
        /// <returns></returns>
        public virtual async Task<BlobDirectory> EnsureDirectoryAsync(string path, bool fetch=false)
        {
            BlobDirectory ret = null;
            if (fetch)
            {
               ret =  cacheDirectory.FirstOrDefault(x => x.Path == path);
               if (ret != null) return ret;
            }
            ret = new BlobDirectory(this, path);
            await ret.GetMetadataAsync(fetch);
            if (fetch)
            {
                cacheDirectory.Add(ret);
            }
            return ret;
        }

        private List<BlobDirectory> cacheDirectory = new List<BlobDirectory>();


        /// <summary>
        /// Blobファイルオブジェクトを生成する
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fetch"></param>
        /// <returns></returns>
        public virtual async Task<BlobFile> EnsureFileAsync(string path, bool fetch = false)
        {
            BlobFile ret = null;
            if (fetch)
            {
                ret = cacheFile.FirstOrDefault(x => x.Path == path);
                if (ret != null) return ret;
            }

            ret = new BlobFile(this, path);
            await ret.GetMetadataAsync(fetch);
            if (fetch)
            {
                cacheFile.Add(ret);
            }
            return ret;
        }

        private List<BlobFile> cacheFile = new List<BlobFile>();

        public virtual void ClearCache()
        {
            cacheFile.Clear();
            cacheDirectory.Clear();
        }

        /// <summary>
        /// 指定したファイルが存在するか
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public abstract Task<bool> ExistsAsync(string path);


        /// <summary>
        /// Blobのコピー
        /// </summary>
        /// <param name="targetPath"></param>
        /// <param name="fromUri"></param>
        /// <returns></returns>
        public abstract Task CopyAsync(BlobFile srcFile, string targetPath);

        /// <summary>
        /// Blobをスナップショット付きでコピー
        /// </summary>
        /// <param name="src"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        public abstract Task CopyWithSnapshotAsync(BlobFile src, BlobFile target);

        /// <summary>
        /// 削除
        /// </summary>
        /// <returns></returns>
        public abstract Task<bool> DeleteAsync(BlobItem file);


        /// <summary>
        /// 完全削除（本体・履歴）
        /// </summary>
        public abstract Task DeleteBlobAsync(BlobItem file);

        /// <summary>
        /// 回復
        /// </summary>
        public abstract Task<bool> RecoverAsync(BlobItem file);

        /// <summary>
        /// 全てのバージョンを取得する
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public abstract Task<List<BlobFile>> GetHistoriesAsync(string id);

        /// <summary>
        /// ディレクトリののファイル一覧を取得する
        /// </summary>
        /// <param name="id"></param>
        /// <param name="maxSize"></param>
        /// <returns></returns>
        public abstract Task<List<BlobItem>> GetFiles(string id, int maxSize, bool flat = false, bool deleted = false);

        /// <summary>
        /// メタ情報の設定
        /// </summary>
        /// <returns></returns>
        public abstract Task SetMetadataAsync(BlobItem item);

        /// <summary>
        /// メタ情報の取得
        /// </summary>
        /// <param name="fetch"></param>
        /// <returns></returns>
        public abstract Task GetMetadataAsync(BlobItem item, bool fetch = true);

        /// <summary>
        /// アップロード
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public abstract Task UploadAsync(BlobItem item, Stream stream);

        /// <summary>
        /// アップロード
        /// </summary>
        /// <param name="localpath"></param>
        /// <returns></returns>
        public abstract Task UploadAsync(BlobItem item, string localpath);


        /// <summary>
        /// バックアップ
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public abstract Task<CloudBlockBlob> CreateArchiveAsync(BlobItem item);

        /// <summary>
        /// バックアップのパージ
        /// </summary>
        /// <param name="item"></param>
        /// <param name="maxsize"></param>
        /// <returns></returns>
        public abstract Task PurgeBackupAsync(BlobItem item, int maxsize=20);

        /// <summary>
        /// ダウンロード
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public abstract Task DownloadAsync(BlobItem item, Stream stream);

        /// <summary>
        /// ダウンロード
        /// </summary>
        /// <param name="localpath"></param>
        /// <returns></returns>
        public abstract Task DownloadAsync(BlobItem item, string localpath);

        /// <summary>
        /// アーカイブのダウンロード
        /// </summary>
        /// <param name="item"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        public abstract Task DownloadArchiveAsync(BlobItem item, Stream stream);

        /// <summary>
        /// フォルダの作成
        /// </summary>
        /// <param name="dire"></param>
        /// <returns></returns>
        public abstract Task CreateDirectoryAsync(BlobDirectory dire);


        /// <summary>
        /// コンテナの削除
        /// </summary>
        /// <returns></returns>
        public abstract bool Destory();

        /// <summary>
        /// チェックイン
        /// </summary>
        /// <returns></returns>
        public abstract Task<bool> CheckInActionAsync(BlobUser user, BlobFile file);

        /// <summary>
        /// チェックアウト
        /// </summary>
        /// <returns></returns>
        public abstract Task<bool> CheckOutActionAsync(BlobUser user, BlobFile file);

        public abstract Task<List<BlobItem>> ListTempFile(string id);

        public abstract Task LoadTempFile(BlobItem item, Stream stream);

        public abstract Task SaveTempFile(BlobItem item, Stream stream);

        public abstract Task DeleteTempFile(BlobItem item);

        public virtual string GetOriginalUrl(string path)
        {
            return null;
        }

        public virtual CustomAuthInfo GetCustomAuth(string path)
        {
            return null;
        }

        public virtual void SetCustomAuth(CustomAuthInfo authInfo)
        {
        }

        public abstract string CreateBlobSas(double expiryHour, bool canWrite);

        /// <summary>
        /// 後処理
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
        }

    }


}
